/**
 *    Copyright 2009-2020 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.session;

import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.builder.CacheRefResolver;
import org.apache.ibatis.builder.IncompleteElementException;
import org.apache.ibatis.builder.ResultMapResolver;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.decorators.LruCache;
import org.apache.ibatis.cache.decorators.SoftCache;
import org.apache.ibatis.cache.decorators.WeakCache;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import org.apache.ibatis.executor.*;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.loader.ProxyFactory;
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.LanguageDriverRegistry;
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.util.*;
import java.util.function.BiFunction;

/**
 * Mybatis配置类
 * 提供了Mybatis所有的配置以及Mapper文件的元数据容器
 *
 * @author Clinton Begin
 */
public class Configuration {

    /**
     * 环境信息,包括事务和数据源等数据
     */
    protected Environment environment;

    /**
     * 是否允许在嵌套语句中使用{@link RowBounds}执行分页操作
     * 如果允许使用则设置为false,看好了，允许使用是False。
     */
    protected boolean safeRowBoundsEnabled;
    /**
     * 是否允许在嵌套语句中使用{@link ResultHandler}返回结果处理器.
     * !! 如果允许使用则设置为false。
     */
    protected boolean safeResultHandlerEnabled = true;
    /**
     * 将下划线转换为驼峰
     * 是否开启自动驼峰命名规则（camel case）映射，即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射
     */
    protected boolean mapUnderscoreToCamelCase;
    /**
     * 是否允许在在方法调用时直接加载该对象的所有属性
     * 当开启时，任何方法的调用都会加载该对象的所有属性。否则，每个属性会按需加载（参考lazyLoadTriggerMethods).
     *
     * @see #lazyLoadTriggerMethods
     */
    protected boolean aggressiveLazyLoading;
    /**
     * 是否允许单条语句返回多个结果集
     */
    protected boolean multipleResultSetsEnabled = true;
    /**
     * 是否允许JDBC自动生成主键
     */
    protected boolean useGeneratedKeys;
    /**
     * 使用列标签代替列名
     */
    protected boolean useColumnLabel = true;
    /**
     * 是否启用缓存
     * 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。
     */
    protected boolean cacheEnabled = true;
    /**
     * 指定当结果集中值为 null 的时候是否调用映射对象的 setter（map 对象时为 put）方法，
     * 这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。
     * 注意基本类型（int、boolean等）是不能设置成 null 的。
     */
    protected boolean callSettersOnNulls;
    /**
     * 是否使用允许使用方法签名中的名称作为语句参数名称,一定程度上可以减少{@link org.apache.ibatis.annotations.Param}的代码
     */
    protected boolean useActualParamName = true;
    /**
     * 当返回行的所有列都是空时，MyBatis默认返回null。 当开启这个设置时，MyBatis会返回一个空实例。
     * 需要注意的是，他也适用于嵌套的结果集（collection和association）.
     */
    protected boolean returnInstanceForEmptyRow;
    /**
     * 指定 MyBatis 增加到日志名称的前缀。
     */
    protected String logPrefix;
    /**
     * 日志实现类,如果未实现则自动查找
     */
    protected Class<? extends Log> logImpl;
    /**
     * 虚拟文件系统，提供了一个访问系统文件资源的简单API,
     * 对当前使用的VFS实例类型进行记录
     */
    protected Class<? extends VFS> vfsImpl;
    /**
     * 缓存的生命周期，对应LocalCacheScope枚举类。
     * MyBatis 利用本地缓存机制（Local Cache）防止循环引用（circular references）和加速重复嵌套查询。
     * 默认值为 SESSION，这种情况下会缓存一个会话中执行的所有查询.
     * 若设置值为 STATEMENT，本地会话仅用在语句执行上，对相同 SqlSession 的不同调用将不会共享数据。
     */
    protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
    /**
     * 在没有为参数指定JDBC类型时,在该参数为null的时候，默认使用的JDBC类型，通常使用NULL,VARCHAR,OTHER.
     */
    protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
    /**
     * 懒加载的触发方法，指定哪个对象的哪些方法触发一次延迟加载。
     */
    protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
    /**
     * {@link java.sql.Statement}的默认超时时间,他决定了驱动等待数据库响应的秒数，默认不超时
     */
    protected Integer defaultStatementTimeout;
    /**
     * 获取数据的默认大小
     * 为驱动的结果集设置默认获取数量。
     * 该参数只可以在查询语句中被覆盖.
     */
    protected Integer defaultFetchSize;
    /**
     * 执行语句时使用的执行器的行为类型
     * 其中:
     * {@link ExecutorType#SIMPLE} 会为每个语句的执行都创建一个新的预处理语句({@link java.sql.PreparedStatement})
     * {@link ExecutorType#REUSE} 会复用预处理语句
     * {@link ExecutorType#BATCH} 会复用预处理语句并执行批量操作
     */
    protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
    /**
     * 定义Mybatis如何自动将JDBC列转换为字段或者属性，它对应AutoMappingBehavior枚举类，其中
     * {@link AutoMappingBehavior#NONE} 禁用自动映射
     * {@link AutoMappingBehavior#PARTIAL} 局部自动映射，只映射没有定义嵌套结果集映射的结果集
     * {@link AutoMappingBehavior#FULL} 完整自动映射，会自动映射任意复杂的结果集(无论是否嵌套)
     */
    protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
    /**
     * 当自动映射遇到无法识别的字段的时候的处理行为
     * {@link AutoMappingUnknownColumnBehavior#NONE} 不做任何操作
     * {@link AutoMappingUnknownColumnBehavior#WARNING} 输出警告日志
     * {@link AutoMappingUnknownColumnBehavior#FAILING} 终止自动映射并抛出异常
     */
    protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
    /**
     * 属性配置 configuration->settings下的属性
     */
    protected Properties variables = new Properties();
    /**
     * 配置反射工厂，简化操作属性和构造器
     */
    protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    /**
     * 配置对象创建工厂
     */
    protected ObjectFactory objectFactory = new DefaultObjectFactory();
    /**
     * 配置对象包装器工厂，主要用于将java对象包装成{@link org.apache.ibatis.reflection.wrapper.ObjectWrapper}
     */
    protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
    /**
     * 是否启用懒加载。当开启时，所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。
     */
    protected boolean lazyLoadingEnabled = false;
    /**
     * 代理工厂，指定Mybatis创建懒加载对象使用的代理工厂，默认使用JavassistProxyFactory.
     */
    protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
    /**
     * 数据库类型唯一标志，Mybatis根据能够根据不能的数据库厂商执行不同的语句，实现此功能就是依赖于该标志。
     */
    protected String databaseId;
    /**
     * 指定一个提供Configuration实例的类。
     * 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。
     * 这个类必须包含一个签名方法static Configuration getConfiguration().
     *
     * @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300 (google code)</a>
     */
    protected Class<?> configurationFactory;
    /**
     * 映射器(Dao操作对象)注册表
     */
    protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
    /**
     * 插件拦截链(Mybatis插件)
     */
    protected final InterceptorChain interceptorChain = new InterceptorChain();
    /**
     * 类型处理器注册表
     */
    protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
    /**
     * 类型别名注册表，主要用在执行SQL语句的出入参以及一些类的简写
     */
    protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
    /**
     * 语言支持驱动注册表
     */
    protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
    /**
     * 声明语句映射表
     */
    protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
            .conflictMessageProducer((savedValue, targetValue) ->
                    ". please check " + savedValue.getResource() + " and " + targetValue.getResource());
    /**
     * 缓存对象注册表
     */
    protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
    /**
     * ResultMap映射表
     */
    protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
    /**
     * 参数映射表
     */
    protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
    /**
     * 主键生成器映射表
     */
    protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");

    /**
     * 已加载过得资源集合，可以用来防止重复加载文件
     */
    protected final Set<String> loadedResources = new HashSet<>();
    /**
     * 代码块映射集合
     */
    protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");

    /**
     * 未完成处理的声明语句
     */
    protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
    /**
     * 未完成处理的缓存引用
     */
    protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
    /**
     * 未完成处理的返回结果映射
     */
    protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
    /**
     * 未完成处理的方法集合
     */
    protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();

    /*
     * 缓存引用映射关系
     * 缓存引用方=》缓存
     * A map holds cache-ref relationship. The key is the namespace that
     * references a cache bound to another namespace and the value is the
     * namespace which the actual cache is bound to.
     */
    protected final Map<String, String> cacheRefMap = new HashMap<>();

    public Configuration(Environment environment) {
        this();
        this.environment = environment;
    }

    public Configuration() {
        // 注册别名

        // 注册JDBC别名
        typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        // 注册事务管理别名
        typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        // 注册JNDI别名
        typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        // 注册池化数据源别名
        typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        // 注册为池化的数据源
        typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
        // 注册永久缓存
        typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        // 注册先入先出的缓存
        typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        // 注册最近最少使用缓存
        typeAliasRegistry.registerAlias("LRU", LruCache.class);
        // 注册软缓存
        typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        // 注册弱缓存
        typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
        // 注册处理数据库ID的提供者
        typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
        // 注册基于XML的语言驱动
        typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        //注册静态语言驱动(通常无需使用)
        typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
        // 注册Sl4j日志
        typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        //注册Commons日志
        typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        //注册log4j日志
        typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        //注册log4j2日志
        typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        //注册jdk log日志
        typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        //注册标准输出日志
        typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        //注册无日志
        typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
        // 注册CGLIB
        typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        // 注册JAVASSIST
        typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
        // 默认使用XML语言驱动
        languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
        // 支持原始语言驱动
        languageRegistry.register(RawLanguageDriver.class);
    }

    public String getLogPrefix() {
        return logPrefix;
    }

    public void setLogPrefix(String logPrefix) {
        this.logPrefix = logPrefix;
    }

    public Class<? extends Log> getLogImpl() {
        return logImpl;
    }

    public void setLogImpl(Class<? extends Log> logImpl) {
        if (logImpl != null) {
            // 缓存记录当前日志实现类
            this.logImpl = logImpl;
            // 更新具体的日志实现
            LogFactory.useCustomLogging(this.logImpl);
        }
    }

    public Class<? extends VFS> getVfsImpl() {
        return this.vfsImpl;
    }

    /**
     * 新增一个VFS实例
     *
     * @param vfsImpl VFS实例
     */
    public void setVfsImpl(Class<? extends VFS> vfsImpl) {
        if (vfsImpl != null) {
            this.vfsImpl = vfsImpl;
            // 添加一个新的VFS实例
            VFS.addImplClass(this.vfsImpl);
        }
    }

    public boolean isCallSettersOnNulls() {
        return callSettersOnNulls;
    }

    public void setCallSettersOnNulls(boolean callSettersOnNulls) {
        this.callSettersOnNulls = callSettersOnNulls;
    }

    public boolean isUseActualParamName() {
        return useActualParamName;
    }

    public void setUseActualParamName(boolean useActualParamName) {
        this.useActualParamName = useActualParamName;
    }

    public boolean isReturnInstanceForEmptyRow() {
        return returnInstanceForEmptyRow;
    }

    public void setReturnInstanceForEmptyRow(boolean returnEmptyInstance) {
        this.returnInstanceForEmptyRow = returnEmptyInstance;
    }

    public String getDatabaseId() {
        return databaseId;
    }

    public void setDatabaseId(String databaseId) {
        this.databaseId = databaseId;
    }

    public Class<?> getConfigurationFactory() {
        return configurationFactory;
    }

    public void setConfigurationFactory(Class<?> configurationFactory) {
        this.configurationFactory = configurationFactory;
    }

    public boolean isSafeResultHandlerEnabled() {
        return safeResultHandlerEnabled;
    }

    public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
        this.safeResultHandlerEnabled = safeResultHandlerEnabled;
    }

    public boolean isSafeRowBoundsEnabled() {
        return safeRowBoundsEnabled;
    }

    public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
        this.safeRowBoundsEnabled = safeRowBoundsEnabled;
    }

    public boolean isMapUnderscoreToCamelCase() {
        return mapUnderscoreToCamelCase;
    }

    public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
        this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
    }

    public void addLoadedResource(String resource) {
        loadedResources.add(resource);
    }

    public boolean isResourceLoaded(String resource) {
        return loadedResources.contains(resource);
    }

    public Environment getEnvironment() {
        return environment;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    public AutoMappingBehavior getAutoMappingBehavior() {
        return autoMappingBehavior;
    }

    public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
        this.autoMappingBehavior = autoMappingBehavior;
    }

    /**
     * @since 3.4.0
     */
    public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
        return autoMappingUnknownColumnBehavior;
    }

    /**
     * @since 3.4.0
     */
    public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
        this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
    }

    public boolean isLazyLoadingEnabled() {
        return lazyLoadingEnabled;
    }

    public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
        this.lazyLoadingEnabled = lazyLoadingEnabled;
    }

    public ProxyFactory getProxyFactory() {
        return proxyFactory;
    }

    public void setProxyFactory(ProxyFactory proxyFactory) {
        if (proxyFactory == null) {
            proxyFactory = new JavassistProxyFactory();
        }
        this.proxyFactory = proxyFactory;
    }

    public boolean isAggressiveLazyLoading() {
        return aggressiveLazyLoading;
    }

    public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
        this.aggressiveLazyLoading = aggressiveLazyLoading;
    }

    public boolean isMultipleResultSetsEnabled() {
        return multipleResultSetsEnabled;
    }

    public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
        this.multipleResultSetsEnabled = multipleResultSetsEnabled;
    }

    public Set<String> getLazyLoadTriggerMethods() {
        return lazyLoadTriggerMethods;
    }

    public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
        this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
    }

    public boolean isUseGeneratedKeys() {
        return useGeneratedKeys;
    }

    public void setUseGeneratedKeys(boolean useGeneratedKeys) {
        this.useGeneratedKeys = useGeneratedKeys;
    }

    public ExecutorType getDefaultExecutorType() {
        return defaultExecutorType;
    }

    public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
        this.defaultExecutorType = defaultExecutorType;
    }

    public boolean isCacheEnabled() {
        return cacheEnabled;
    }

    public void setCacheEnabled(boolean cacheEnabled) {
        this.cacheEnabled = cacheEnabled;
    }

    public Integer getDefaultStatementTimeout() {
        return defaultStatementTimeout;
    }

    public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
        this.defaultStatementTimeout = defaultStatementTimeout;
    }

    /**
     * @since 3.3.0
     */
    public Integer getDefaultFetchSize() {
        return defaultFetchSize;
    }

    /**
     * @since 3.3.0
     */
    public void setDefaultFetchSize(Integer defaultFetchSize) {
        this.defaultFetchSize = defaultFetchSize;
    }

    public boolean isUseColumnLabel() {
        return useColumnLabel;
    }

    public void setUseColumnLabel(boolean useColumnLabel) {
        this.useColumnLabel = useColumnLabel;
    }

    public LocalCacheScope getLocalCacheScope() {
        return localCacheScope;
    }

    public void setLocalCacheScope(LocalCacheScope localCacheScope) {
        this.localCacheScope = localCacheScope;
    }

    public JdbcType getJdbcTypeForNull() {
        return jdbcTypeForNull;
    }

    public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
        this.jdbcTypeForNull = jdbcTypeForNull;
    }

    public Properties getVariables() {
        return variables;
    }

    public void setVariables(Properties variables) {
        this.variables = variables;
    }

    /**
     * 获取类型处理器注册表
     */
    public TypeHandlerRegistry getTypeHandlerRegistry() {
        return typeHandlerRegistry;
    }

    /**
     * 配置枚举类型的默认的TypeHandler，默认使用EnumTypeHandler。
     *
     * @param typeHandler 用于处理枚举类型的类型处理器
     * @since 3.4.5
     */
    public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {
        if (typeHandler != null) {
            // 获取类型处理器注册表，并设置默认的枚举类型处理器
            getTypeHandlerRegistry().setDefaultEnumTypeHandler(typeHandler);
        }
    }

    public TypeAliasRegistry getTypeAliasRegistry() {
        return typeAliasRegistry;
    }

    /**
     * @since 3.2.2
     */
    public MapperRegistry getMapperRegistry() {
        return mapperRegistry;
    }

    public ReflectorFactory getReflectorFactory() {
        return reflectorFactory;
    }

    public void setReflectorFactory(ReflectorFactory reflectorFactory) {
        this.reflectorFactory = reflectorFactory;
    }

    public ObjectFactory getObjectFactory() {
        return objectFactory;
    }

    /**
     * 配置对象创建工厂
     *
     * @param objectFactory 对象创建工厂
     */
    public void setObjectFactory(ObjectFactory objectFactory) {
        this.objectFactory = objectFactory;
    }

    public ObjectWrapperFactory getObjectWrapperFactory() {
        return objectWrapperFactory;
    }

    /**
     * 配置对象包装工厂
     * @param objectWrapperFactory 对象包装工厂
     */
    public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
        this.objectWrapperFactory = objectWrapperFactory;
    }

    /**
     * @since 3.2.2
     */
    public List<Interceptor> getInterceptors() {
        return interceptorChain.getInterceptors();
    }

    public LanguageDriverRegistry getLanguageRegistry() {
        return languageRegistry;
    }

    /**
     * 设置Mybatis的Sql默认脚本语言处理器
     *
     * @param driver 脚本语言处理器
     */
    public void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {
        if (driver == null) {
            driver = XMLLanguageDriver.class;
        }
        // 往脚本语言处理器注册表中注册默认的脚本语言处理器
        getLanguageRegistry().setDefaultDriverClass(driver);
    }

    public LanguageDriver getDefaultScriptingLanguageInstance() {
        return languageRegistry.getDefaultDriver();
    }

    /**
     * @deprecated Use {@link #getDefaultScriptingLanguageInstance()}
     */
    @Deprecated
    public LanguageDriver getDefaultScriptingLanuageInstance() {
        return getDefaultScriptingLanguageInstance();
    }

    /**
     * 生成一个新的对象元数据
     *
     * @param object 原始对象
     */
    public MetaObject newMetaObject(Object object) {
        return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }

    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        // 使用当前映射语句对应的语句解析器来生成ParameterHandler
        ParameterHandler parameterHandler = mappedStatement
                .getLang()
                .createParameterHandler(mappedStatement, parameterObject, boundSql);
        // 调用参数处理器插件
        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
        // 返回参数处理器
        return parameterHandler;
    }

    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                                ResultHandler resultHandler, BoundSql boundSql) {
        // 生成返回结果处理器
        ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
        // 应用返回结果处理器插件
        resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
        return resultSetHandler;
    }

    /**
     * 新建一个Statement处理器
     *
     * @param executor        SQL执行器
     * @param mappedStatement statement语句映射对象
     * @param parameterObject 入参对象
     * @param rowBounds       分页对象
     * @param resultHandler   返回结果处理对象
     * @param boundSql        SQL对象
     * @return 一个Statement处理器
     */
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 获取一个Statement处理器
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

        //  交由Mybatis插件来处理
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

        // 返回Statement处理器
        return statementHandler;
    }

    public Executor newExecutor(Transaction transaction) {
        return newExecutor(transaction, defaultExecutorType);
    }

    /**
     * 构建一个Sql执行器
     *
     * @param transaction  事务
     * @param executorType 执行类型
     * @return SQL执行器
     */
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        // 配置执行器类型
        executorType = executorType == null ? defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Executor executor;

        // 实例化执行器
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }

        if (cacheEnabled) {

            // 如果开启了缓存，在执行器外包装缓存
            executor = new CachingExecutor(executor);
        }
        // 切入插件职责链
        executor = (Executor) interceptorChain.pluginAll(executor);

        return executor;
    }

    public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
        keyGenerators.put(id, keyGenerator);
    }

    public Collection<String> getKeyGeneratorNames() {
        return keyGenerators.keySet();
    }

    public Collection<KeyGenerator> getKeyGenerators() {
        return keyGenerators.values();
    }

    public KeyGenerator getKeyGenerator(String id) {
        return keyGenerators.get(id);
    }

    public boolean hasKeyGenerator(String id) {
        return keyGenerators.containsKey(id);
    }

    public void addCache(Cache cache) {
        caches.put(cache.getId(), cache);
    }

    public Collection<String> getCacheNames() {
        return caches.keySet();
    }

    public Collection<Cache> getCaches() {
        return caches.values();
    }

    public Cache getCache(String id) {
        return caches.get(id);
    }

    public boolean hasCache(String id) {
        return caches.containsKey(id);
    }

    public void addResultMap(ResultMap rm) {
        resultMaps.put(rm.getId(), rm);
        /*检查当前resultMap内的鉴别器是否嵌套ResultMap*/
        checkLocallyForDiscriminatedNestedResultMaps(rm);
        /*检查所有的ResultMap内的鉴别器是否嵌套ResultMap*/
        checkGloballyForDiscriminatedNestedResultMaps(rm);
    }

    public Collection<String> getResultMapNames() {
        return resultMaps.keySet();
    }

    public Collection<ResultMap> getResultMaps() {
        return resultMaps.values();
    }

    public ResultMap getResultMap(String id) {
        return resultMaps.get(id);
    }

    public boolean hasResultMap(String id) {
        return resultMaps.containsKey(id);
    }

    public void addParameterMap(ParameterMap pm) {
        parameterMaps.put(pm.getId(), pm);
    }

    public Collection<String> getParameterMapNames() {
        return parameterMaps.keySet();
    }

    public Collection<ParameterMap> getParameterMaps() {
        return parameterMaps.values();
    }

    public ParameterMap getParameterMap(String id) {
        return parameterMaps.get(id);
    }

    public boolean hasParameterMap(String id) {
        return parameterMaps.containsKey(id);
    }

    public void addMappedStatement(MappedStatement ms) {
        mappedStatements.put(ms.getId(), ms);
    }

    public Collection<String> getMappedStatementNames() {
        buildAllStatements();
        return mappedStatements.keySet();
    }

    public Collection<MappedStatement> getMappedStatements() {
        buildAllStatements();
        return mappedStatements.values();
    }

    public Collection<XMLStatementBuilder> getIncompleteStatements() {
        return incompleteStatements;
    }

    public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
        incompleteStatements.add(incompleteStatement);
    }

    public Collection<CacheRefResolver> getIncompleteCacheRefs() {
        return incompleteCacheRefs;
    }

    public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
        incompleteCacheRefs.add(incompleteCacheRef);
    }

    public Collection<ResultMapResolver> getIncompleteResultMaps() {
        return incompleteResultMaps;
    }

    public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
        incompleteResultMaps.add(resultMapResolver);
    }

    public void addIncompleteMethod(MethodResolver builder) {
        incompleteMethods.add(builder);
    }

    public Collection<MethodResolver> getIncompleteMethods() {
        return incompleteMethods;
    }

    /**
     * 根据映射声明语句的唯一标志获取映射声明语句
     *
     * @param id 唯一标志
     * @return 映射声明语句
     */
    public MappedStatement getMappedStatement(String id) {

        return this.getMappedStatement(id, true);
    }

    /**
     * 根据映射声明语句的唯一标志获取映射声明语句
     *
     * @param id                           唯一标志
     * @param validateIncompleteStatements 是否校验未完成解析的声明语句
     * @return 映射声明语句
     */
    public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
        if (validateIncompleteStatements) {
            // 解析之前所有未完成解析的节点
            buildAllStatements();
        }
        // 获取声明语句
        return mappedStatements.get(id);
    }

    public Map<String, XNode> getSqlFragments() {
        return sqlFragments;
    }

    /**
     * 添加一个拦截器
     *
     * @param interceptor 拦截器
     */
    public void addInterceptor(Interceptor interceptor) {
        interceptorChain.addInterceptor(interceptor);
    }

    public void addMappers(String packageName, Class<?> superType) {
        mapperRegistry.addMappers(packageName, superType);
    }

    public void addMappers(String packageName) {
        mapperRegistry.addMappers(packageName);
    }

    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

    /**
     * 获取映射器
     *
     * @param type       需要获取的映射器类型
     * @param sqlSession 会话
     * @param <T>        泛型
     * @return 映射器实例
     */
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 委托给MapperRegistry对象完成获取映射器的工作
        return mapperRegistry.getMapper(type, sqlSession);
    }

    public boolean hasMapper(Class<?> type) {
        return mapperRegistry.hasMapper(type);
    }

    public boolean hasStatement(String statementName) {
        return hasStatement(statementName, true);
    }

    public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
        if (validateIncompleteStatements) {
            buildAllStatements();
        }
        return mappedStatements.containsKey(statementName);
    }

    public void addCacheRef(String namespace, String referencedNamespace) {
        cacheRefMap.put(namespace, referencedNamespace);
    }

    /**
     * 解析所有未完成的语句节点(快速失败)
     * Parses all the unprocessed statement nodes in the cache. It is recommended
     * to call this method once all the mappers are added as it provides fail-fast
     * statement validation.
     */
    protected void buildAllStatements() {
        parsePendingResultMaps();
        // 解析未完成的缓存引用
        if (!incompleteCacheRefs.isEmpty()) {
            synchronized (incompleteCacheRefs) {
                incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
            }
        }
        // 解析未完成的声明语句
        if (!incompleteStatements.isEmpty()) {
            synchronized (incompleteStatements) {
                incompleteStatements.removeIf(x -> {
                    x.parseStatementNode();
                    return true;
                });
            }
        }
        // 解析未完成的方法
        if (!incompleteMethods.isEmpty()) {
            synchronized (incompleteMethods) {
                incompleteMethods.removeIf(x -> {
                    x.resolve();
                    return true;
                });
            }
        }
    }

    private void parsePendingResultMaps() {
        if (incompleteResultMaps.isEmpty()) {
            return;
        }
        synchronized (incompleteResultMaps) {
            boolean resolved;
            IncompleteElementException ex = null;
            do {
                resolved = false;
                Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();
                while (iterator.hasNext()) {
                    try {
                        iterator.next().resolve();
                        iterator.remove();
                        resolved = true;
                    } catch (IncompleteElementException e) {
                        ex = e;
                    }
                }
            } while (resolved);
            if (!incompleteResultMaps.isEmpty() && ex != null) {
                // At least one result map is unresolvable.
                throw ex;
            }
        }
    }

    /*
     * Extracts namespace from fully qualified statement id.
     *
     * @param statementId
     * @return namespace or null when id does not contain period.
     */
    protected String extractNamespace(String statementId) {
        int lastPeriod = statementId.lastIndexOf('.');
        return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
    }

    // Slow but a one time cost. A better solution is welcome.
    protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
        if (rm.hasNestedResultMaps()) {
            // 当前的ResultMap有嵌套ResultMap
            for (Map.Entry<String, ResultMap> entry : resultMaps.entrySet()) {
                // 遍历处理全局已加载的resultMap
                Object value = entry.getValue();
                if (value instanceof ResultMap) {
                    ResultMap entryResultMap = (ResultMap) value;
                    if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
                        // 已经加载了鉴别器对应的ResultMap
                        Collection<String> discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap().values();
                        // 获取鉴别器引用了当前的resultMap
                        if (discriminatedResultMapNames.contains(rm.getId())) {
                            // 更新entryResultMap的hasNestedResultMaps字段为true.
                            entryResultMap.forceNestedResultMaps();
                        }
                    }
                }
            }
        }
    }

    // Slow but a one time cost. A better solution is welcome.
    protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
        if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
            // 当前ResultMap不含有嵌套的ResultMap，同时含有鉴别器
            for (Map.Entry<String, String> entry : rm.getDiscriminator().getDiscriminatorMap().entrySet()) {
                // 获取鉴别器对应的ResultMap
                String discriminatedResultMapName = entry.getValue();

                // 已经加载了鉴别器对应的ResultMap
                if (hasResultMap(discriminatedResultMapName)) {
                    // 获取鉴别器对应的ResultMap
                    ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);

                    if (discriminatedResultMap.hasNestedResultMaps()) {
                        // 更新ResultMap的hasNestedResultMaps字段为true.
                        rm.forceNestedResultMaps();
                        break;
                    }
                }
            }
        }
    }

    /**
     * 扩展了HashMap主要是针对Mybatis进行了进一步的封装，在设值和取值的时候均有可能会触发业务异常
     *
     * @param <V> 泛型
     */
    protected static class StrictMap<V> extends HashMap<String, V> {

        private static final long serialVersionUID = -4950446264854982944L;
        private final String name;
        private BiFunction<V, V, String> conflictMessageProducer;

        public StrictMap(String name, int initialCapacity, float loadFactor) {
            super(initialCapacity, loadFactor);
            this.name = name;
        }

        public StrictMap(String name, int initialCapacity) {
            super(initialCapacity);
            this.name = name;
        }

        public StrictMap(String name) {
            super();
            this.name = name;
        }

        public StrictMap(String name, Map<String, ? extends V> m) {
            super(m);
            this.name = name;
        }

        /**
         * Assign a function for producing a conflict error message when contains value with the same key.
         * <p>
         * function arguments are 1st is saved value and 2nd is target value.
         *
         * @param conflictMessageProducer A function for producing a conflict error message
         * @return a conflict error message
         * @since 3.5.0
         */
        public StrictMap<V> conflictMessageProducer(BiFunction<V, V, String> conflictMessageProducer) {
            this.conflictMessageProducer = conflictMessageProducer;
            return this;
        }

        @SuppressWarnings("unchecked")
        public V put(String key, V value) {
            if (containsKey(key)) {
                throw new IllegalArgumentException(name + " already contains value for " + key
                        + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
            }
            if (key.contains(".")) {
                final String shortKey = getShortName(key);
                if (super.get(shortKey) == null) {
                    super.put(shortKey, value);
                } else {
                    super.put(shortKey, (V) new Ambiguity(shortKey));
                }
            }
            return super.put(key, value);
        }

        public V get(Object key) {
            V value = super.get(key);
            if (value == null) {
                throw new IllegalArgumentException(name + " does not contain value for " + key);
            }
            if (value instanceof Ambiguity) {
                throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
                        + " (try using the full name including the namespace, or rename one of the entries)");
            }
            return value;
        }

        private String getShortName(String key) {
            final String[] keyParts = key.split("\\.");
            return keyParts[keyParts.length - 1];
        }

        protected static class Ambiguity {
            final private String subject;

            public Ambiguity(String subject) {
                this.subject = subject;
            }

            public String getSubject() {
                return subject;
            }
        }
    }

}
